#ifndef V2_NIM_INTERNAL_H
#define V2_NIM_INTERNAL_H
#include "v2_nim_utilities.hpp"
#ifndef WIN32
#include <dlfcn.h>
#endif
namespace v2 {
inline V2NIMError::V2NIMError(uint32_t code, std::pair<nstd::string, nstd::string> pair)
    : code(code) {
    auto iter = V2NIM_ERROR_DESC_MAPPING.find(code);
    if (iter != V2NIM_ERROR_DESC_MAPPING.end()) {
        desc = iter->second;
    }
    if (!pair.first.empty()) {
        detail.emplace(std::move(pair));
    }
}
inline nstd::string& V2NIMError::operator[](const nstd::string& key) {
    return detail[key];
}
namespace internal {
enum {
    V2_NIM_INTERNEL_INSTANCE = 0,
    V2_NIM_INTERNEL_CLIENT_ANTI_SPAM_UTIL,
    V2_NIM_INTERNEL_CONVERSATION_ID_UTIL,
    V2_NIM_INTERNEL_MESSAGE_UTIL,
};
enum {
    V2_NIM_CHATROOM_SDK_EXPORT = 0,
    V2_NIM_CHATROOM_MESSAGE_UTIL,
};
// V2NIMClientAntispamUtilInternal
class V2NIMClientAntispamUtilInternal {
public:
    virtual V2NIMClientAntispamResult checkTextAntispam(nstd::string text, nstd::string replace) = 0;
};
inline V2NIMClientAntispamUtilInternal* internalClientAntispamUtil{nullptr};

// V2NIMConversationIdUtilInternal
class V2NIMConversationIdUtilInternal {
public:
    virtual nstd::string p2pConversationId(const nstd::string& accountId) = 0;
    virtual nstd::string teamConversationId(const nstd::string& teamId) = 0;
    virtual nstd::string superTeamConversationId(const nstd::string& superTeamId) = 0;
    virtual V2NIMConversationType parseConversationType(const nstd::string& conversationId) = 0;
    virtual nstd::string parseConversationTargetId(const nstd::string& conversationId) = 0;
};
inline V2NIMConversationIdUtilInternal* internalConversationIdUtil{nullptr};

// V2NIMMessageUtilInternal
class V2NIMMessageUtilInternal {
public:
    virtual nstd::optional<V2NIMMessage> createTextMessage(nstd::string text) = 0;
    virtual nstd::optional<V2NIMMessage> createImageMessage(nstd::string imagePath,
        nstd::string name,
        nstd::string sceneName,
        uint32_t width,
        uint32_t height) = 0;
    virtual nstd::optional<V2NIMMessage> createAudioMessage(nstd::string audioPath, nstd::string name, nstd::string sceneName, uint32_t duration) = 0;
    virtual nstd::optional<V2NIMMessage> createVideoMessage(nstd::string videoPath,
        nstd::string name,
        nstd::string sceneName,
        uint32_t duration,
        uint32_t width,
        uint32_t height) = 0;
    virtual nstd::optional<V2NIMMessage> createFileMessage(nstd::string filePath, nstd::string name, nstd::string sceneName) = 0;
    virtual nstd::optional<V2NIMMessage> createLocationMessage(double latitude, double longitude, nstd::string address) = 0;
    virtual nstd::optional<V2NIMMessage> createCustomMessage(nstd::string text, nstd::string rawAttachment) = 0;
    virtual nstd::optional<V2NIMMessage> createTipsMessage(nstd::string text) = 0;
    virtual nstd::optional<V2NIMMessage> createForwardMessage(V2NIMMessage message) = 0;
    virtual nstd::optional<V2NIMMessage> createCallMessage(int32_t type,
        const nstd::string& channelId,
        int32_t status,
        const nstd::vector<V2NIMMessageCallDuration>& durations,
        const nstd::string& text) = 0;
    virtual nstd::optional<nstd::string> messageSerialization(const V2NIMMessage& message) = 0;
    virtual nstd::optional<V2NIMMessage> messageDeserialization(const nstd::string& message) = 0;
    virtual nstd::string imageThumbUrl(const nstd::string& url, int32_t thumbSize) = 0;
    virtual nstd::string videoCoverUrl(const nstd::string& url, int32_t offset, int32_t thumbSize, const nstd::string& type) = 0;
};
inline V2NIMMessageUtilInternal* internalMessageUtil{nullptr};

// V2NIMChatroomMessageUtilInternal
class V2NIMChatroomMessageUtilInternal {
public:
    virtual nstd::optional<V2NIMChatroomMessage> createTextMessage(nstd::string text) = 0;
    virtual nstd::optional<V2NIMChatroomMessage> createImageMessage(nstd::string imagePath,
        nstd::string name,
        nstd::string sceneName,
        uint32_t width,
        uint32_t height) = 0;
    virtual nstd::optional<V2NIMChatroomMessage> createAudioMessage(nstd::string audioPath,
        nstd::string name,
        nstd::string sceneName,
        uint32_t duration) = 0;
    virtual nstd::optional<V2NIMChatroomMessage> createVideoMessage(nstd::string videoPath,
        nstd::string name,
        nstd::string sceneName,
        uint32_t duration,
        uint32_t width,
        uint32_t height) = 0;
    virtual nstd::optional<V2NIMChatroomMessage> createFileMessage(nstd::string filePath, nstd::string name, nstd::string sceneName) = 0;
    virtual nstd::optional<V2NIMChatroomMessage> createLocationMessage(double latitude, double longitude, nstd::string address) = 0;
    virtual nstd::optional<V2NIMChatroomMessage> createCustomMessage(nstd::string rawAttachment) = 0;
    virtual nstd::optional<V2NIMChatroomMessage> createTipsMessage(nstd::string text) = 0;
    virtual nstd::optional<V2NIMChatroomMessage> createForwardMessage(V2NIMChatroomMessage message) = 0;
};
inline V2NIMChatroomMessageUtilInternal* internalChatroomMessageUtil{nullptr};

#ifdef WIN32
static const char* NIM_SDK_NAME = "nim.dll";
static const char* NIM_CHATROOM_SDK_NAME = "nim_chatroom.dll";
#elif __APPLE__
static const char* NIM_SDK_NAME = "libnim.dylib";
static const char* NIM_CHATROOM_SDK_NAME = "libnim_chatroom.dylib";
#else
static const char* NIM_SDK_NAME = "libnim.so";
static const char* NIM_CHATROOM_SDK_NAME = "libnim_chatroom.so";
#endif
template <typename T>
inline T callSdkFunction(const char* sdkName, const char* functionName) {
#ifdef WIN32
    auto* sdkHandle = ::LoadLibraryA(sdkName);
    if (sdkHandle == nullptr) {
        throw std::runtime_error("LoadLibraryA error: " + std::to_string(::GetLastError()));
    }
    auto* instanceFunction = ::GetProcAddress(static_cast<HMODULE>(sdkHandle), functionName);
    if (instanceFunction == nullptr) {
        throw std::runtime_error("GetProcAddress error: " + std::to_string(::GetLastError()));
    }
#else
    auto* sdkHandle = dlopen(sdkName, RTLD_LAZY);
    if (sdkHandle == nullptr) {
        throw std::runtime_error("dlopen error: " + std::string(dlerror()));
    }
    auto* instanceFunction = dlsym(sdkHandle, functionName);
    if (instanceFunction == nullptr) {
        throw std::runtime_error("dlsym error: " + std::string(dlerror()));
    }
#endif
    return reinterpret_cast<T (*)()>(instanceFunction)();
}
}  // namespace internal
inline nstd::optional<V2NIMMessage> V2NIMMessageCreator::createTextMessage(nstd::string text) {
    return internal::internalMessageUtil->createTextMessage(text);
}
inline nstd::optional<V2NIMMessage> V2NIMMessageCreator::createImageMessage(nstd::string imagePath,
    nstd::string name,
    nstd::string sceneName,
    uint32_t width,
    uint32_t height) {
    return internal::internalMessageUtil->createImageMessage(imagePath, name, sceneName, width, height);
}
inline nstd::optional<V2NIMMessage> V2NIMMessageCreator::createAudioMessage(nstd::string audioPath,
    nstd::string name,
    nstd::string sceneName,
    uint32_t duration) {
    return internal::internalMessageUtil->createAudioMessage(audioPath, name, sceneName, duration);
}
inline nstd::optional<V2NIMMessage> V2NIMMessageCreator::createVideoMessage(nstd::string videoPath,
    nstd::string name,
    nstd::string sceneName,
    uint32_t duration,
    uint32_t width,
    uint32_t height) {
    return internal::internalMessageUtil->createVideoMessage(videoPath, name, sceneName, duration, width, height);
}
inline nstd::optional<V2NIMMessage> V2NIMMessageCreator::createFileMessage(nstd::string filePath, nstd::string name, nstd::string sceneName) {
    return internal::internalMessageUtil->createFileMessage(filePath, name, sceneName);
}
inline nstd::optional<V2NIMMessage> V2NIMMessageCreator::createLocationMessage(double latitude, double longitude, nstd::string address) {
    return internal::internalMessageUtil->createLocationMessage(latitude, longitude, address);
}
inline nstd::optional<V2NIMMessage> V2NIMMessageCreator::createCustomMessage(nstd::string text, nstd::string rawAttachment) {
    return internal::internalMessageUtil->createCustomMessage(text, rawAttachment);
}
inline nstd::optional<V2NIMMessage> V2NIMMessageCreator::createTipsMessage(nstd::string text) {
    return internal::internalMessageUtil->createTipsMessage(text);
}
inline nstd::optional<V2NIMMessage> V2NIMMessageCreator::createForwardMessage(V2NIMMessage message) {
    return internal::internalMessageUtil->createForwardMessage(message);
}
inline nstd::optional<V2NIMMessage> V2NIMMessageCreator::createCallMessage(int32_t type,
    const nstd::string& channelId,
    int32_t status,
    const nstd::vector<V2NIMMessageCallDuration>& durations,
    const nstd::string& text) {
    return internal::internalMessageUtil->createCallMessage(type, channelId, status, durations, text);
}

inline nstd::optional<V2NIMChatroomMessage> V2NIMChatroomMessageCreator::createTextMessage(nstd::string text) {
    return internal::internalChatroomMessageUtil->createTextMessage(text);
}
inline nstd::optional<V2NIMChatroomMessage> V2NIMChatroomMessageCreator::createImageMessage(nstd::string imagePath,
    nstd::string name,
    nstd::string sceneName,
    uint32_t width,
    uint32_t height) {
    return internal::internalChatroomMessageUtil->createImageMessage(imagePath, name, sceneName, width, height);
}
inline nstd::optional<V2NIMChatroomMessage> V2NIMChatroomMessageCreator::createAudioMessage(nstd::string audioPath,
    nstd::string name,
    nstd::string sceneName,
    uint32_t duration) {
    return internal::internalChatroomMessageUtil->createAudioMessage(audioPath, name, sceneName, duration);
}
inline nstd::optional<V2NIMChatroomMessage> V2NIMChatroomMessageCreator::createVideoMessage(nstd::string videoPath,
    nstd::string name,
    nstd::string sceneName,
    uint32_t duration,
    uint32_t width,
    uint32_t height) {
    return internal::internalChatroomMessageUtil->createVideoMessage(videoPath, name, sceneName, duration, width, height);
}
inline nstd::optional<V2NIMChatroomMessage> V2NIMChatroomMessageCreator::createFileMessage(nstd::string filePath,
    nstd::string name,
    nstd::string sceneName) {
    return internal::internalChatroomMessageUtil->createFileMessage(filePath, name, sceneName);
}
inline nstd::optional<V2NIMChatroomMessage> V2NIMChatroomMessageCreator::createLocationMessage(double latitude,
    double longitude,
    nstd::string address) {
    return internal::internalChatroomMessageUtil->createLocationMessage(latitude, longitude, address);
}
inline nstd::optional<V2NIMChatroomMessage> V2NIMChatroomMessageCreator::createCustomMessage(nstd::string rawAttachment) {
    return internal::internalChatroomMessageUtil->createCustomMessage(rawAttachment);
}
inline nstd::optional<V2NIMChatroomMessage> V2NIMChatroomMessageCreator::createTipsMessage(nstd::string text) {
    return internal::internalChatroomMessageUtil->createTipsMessage(text);
}
inline nstd::optional<V2NIMChatroomMessage> V2NIMChatroomMessageCreator::createForwardMessage(V2NIMChatroomMessage message) {
    return internal::internalChatroomMessageUtil->createForwardMessage(message);
}
inline nstd::optional<nstd::string> V2NIMMessageConverter::messageSerialization(const V2NIMMessage& message) {
    return internal::internalMessageUtil->messageSerialization(message);
}
inline nstd::optional<V2NIMMessage> V2NIMMessageConverter::messageDeserialization(const nstd::string& message) {
    return internal::internalMessageUtil->messageDeserialization(message);
}
inline nstd::string V2NIMStorageUtil::imageThumbUrl(const nstd::string& url, int32_t thumbSize) {
    return internal::internalMessageUtil->imageThumbUrl(url, thumbSize);
}
inline nstd::string V2NIMStorageUtil::videoCoverUrl(const nstd::string& url, int32_t offset, int32_t thumbSize, const nstd::string& type) {
    return internal::internalMessageUtil->videoCoverUrl(url, offset, thumbSize, type);
}
inline nstd::string V2NIMConversationIdUtil::p2pConversationId(const nstd::string& accountId) {
    return internal::internalConversationIdUtil->p2pConversationId(accountId);
}
inline nstd::string V2NIMConversationIdUtil::teamConversationId(const nstd::string& teamId) {
    return internal::internalConversationIdUtil->teamConversationId(teamId);
}
inline nstd::string V2NIMConversationIdUtil::superTeamConversationId(const nstd::string& superTeamId) {
    return internal::internalConversationIdUtil->superTeamConversationId(superTeamId);
}
inline V2NIMConversationType V2NIMConversationIdUtil::parseConversationType(const nstd::string& conversationId) {
    return internal::internalConversationIdUtil->parseConversationType(conversationId);
}
inline nstd::string V2NIMConversationIdUtil::parseConversationTargetId(const nstd::string& conversationId) {
    return internal::internalConversationIdUtil->parseConversationTargetId(conversationId);
}
inline V2NIMClientAntispamResult V2NIMClientAntispamUtil::checkTextAntispam(nstd::string text, nstd::string replace) {
    return internal::internalClientAntispamUtil->checkTextAntispam(text, replace);
}
}  // namespace v2
#endif
